package com.lxk.netty;

import com.lxk.pojo.Device;
import com.lxk.service.PlayService;
import com.lxk.util.SpringContextHolder;
import com.lxk.util.netty.NettyDataHandler;
import com.lxk.vo.NettyDataVO;
import com.lxk.vo.ScanDataVO;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author JohnSoybean
 */
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /*
    变量：
        deviceNumber:12345678
        排队扫码机：0101
        扫描确认机：0202
        上报命令： F8 0B
        下发命令： FA 0B
        用户ID 1： 4B 46 39 4B 50 6E 66 52 61 64 45 71 48 4A 6D 62 4F 6F 51 39 6F 6F 68 32 5A 37 33 75 52 44 4B 6A 33 71 31 79 46 35 61 4F 64 78 37 43 38 2B 63 76 42 72 2B 32 6A 70 70 43 6C 33 43 36 4A 74 4E 59 66 4E 6B 76 5A 63 67 37 66 33 37 2B 53 50 56 53 38 4F 37 79 4D 51 3D 3D
        用户ID 2： 70 4C 7A 75 51 53 44 47 4A 74 59 4B 6E 5A 68 55 65 7A 4A 45 45 4B 72 42 7A 57 69 65 54 7A 72 56 6E 64 4D 63 33 75 79 52 6A 4B 35 59 38 55 49 37 6C 55 4A 32 73 6F 2B 78 35 2F 4A 33 78 68 53 30 66 69 34 48 71 75 61 2F 4F 6E 75 73 79 50 35 7A 32 2B 50 65 51 51 3D 3D
    测试组：
        1. 连接测试
        A5 A5 5A 5A 2F 31 32 33 34 35 36 37 38 01 01 F8 0B 00 01 01
        2. 心跳上报测试
        A5 A5 5A 5A C6 31 32 33 34 35 36 37 38 01 01 F8 0B 00 02 03 AA
        3. 扫码排队测试
        用户1  A5 A5 5A 5A 92 31 32 33 34 35 36 37 38 01 01 F8 0B 00 5B 02 01 58 4B 46 39 4B 50 6E 66 52 61 64 45 71 48 4A 6D 62 4F 6F 51 39 6F 6F 68 32 5A 37 33 75 52 44 4B 6A 33 71 31 79 46 35 61 4F 64 78 37 43 38 2B 63 76 42 72 2B 32 6A 70 70 43 6C 33 43 36 4A 74 4E 59 66 4E 6B 76 5A 63 67 37 66 33 37 2B 53 50 56 53 38 4F 37 79 4D 51 3D 3D
        用户2  A5 A5 5A 5A 5A 31 32 33 34 35 36 37 38 01 01 F8 0B 00 5B 02 01 58 70 4C 7A 75 51 53 44 47 4A 74 59 4B 6E 5A 68 55 65 7A 4A 45 45 4B 72 42 7A 57 69 65 54 7A 72 56 6E 64 4D 63 33 75 79 52 6A 4B 35 59 38 55 49 37 6C 55 4A 32 73 6F 2B 78 35 2F 4A 33 78 68 53 30 66 69 34 48 71 75 61 2F 4F 6E 75 73 79 50 35 7A 32 2B 50 65 51 51 3D 3D
        4. 扫码确认测试
        用户1  A5 A5 5A 5A 2A 31 32 33 34 35 36 37 38 01 02 F8 0B 00 5B 02 02 58 4B 46 39 4B 50 6E 66 52 61 64 45 71 48 4A 6D 62 4F 6F 51 39 6F 6F 68 32 5A 37 33 75 52 44 4B 6A 33 71 31 79 46 35 61 4F 64 78 37 43 38 2B 63 76 42 72 2B 32 6A 70 70 43 6C 33 43 36 4A 74 4E 59 66 4E 6B 76 5A 63 67 37 66 33 37 2B 53 50 56 53 38 4F 37 79 4D 51 3D 3D
        用户2  A5 A5 5A 5A E2 31 32 33 34 35 36 37 38 01 02 F8 0B 00 5B 02 02 58 70 4C 7A 75 51 53 44 47 4A 74 59 4B 6E 5A 68 55 65 7A 4A 45 45 4B 72 42 7A 57 69 65 54 7A 72 56 6E 64 4D 63 33 75 79 52 6A 4B 35 59 38 55 49 37 6C 55 4A 32 73 6F 2B 78 35 2F 4A 33 78 68 53 30 66 69 34 48 71 75 61 2F 4F 6E 75 73 79 50 35 7A 32 2B 50 65 51 51 3D 3D
        5. 游戏结束测试
        用户1  A5 A5 5A 5A D5 31 32 33 34 35 36 37 38 01 01 F8 0B 00 5A 04 58 4B 46 39 4B 50 6E 66 52 61 64 45 71 48 4A 6D 62 4F 6F 51 39 6F 6F 68 32 5A 37 33 75 52 44 4B 6A 33 71 31 79 46 35 61 4F 64 78 37 43 38 2B 63 76 42 72 2B 32 6A 70 70 43 6C 33 43 36 4A 74 4E 59 66 4E 6B 76 5A 63 67 37 66 33 37 2B 53 50 56 53 38 4F 37 79 4D 51 3D 3D
        用户2  A5 A5 5A 5A 1D 31 32 33 34 35 36 37 38 01 01 F8 0B 00 5A 04 58 70 4C 7A 75 51 53 44 47 4A 74 59 4B 6E 5A 68 55 65 7A 4A 45 45 4B 72 42 7A 57 69 65 54 7A 72 56 6E 64 4D 63 33 75 79 52 6A 4B 35 59 38 55 49 37 6C 55 4A 32 73 6F 2B 78 35 2F 4A 33 78 68 53 30 66 69 34 48 71 75 61 2F 4F 6E 75 73 79 50 35 7A 32 2B 50 65 51 51 3D 3D
     */

    /**
     * 客户端连接会触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel active");
    }

    /**
     * 客户端发消息会触发 不论成功失败 接收到消息后都返回成功
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//        log.info("===== Netty Begin =====");
        PlayService playService = SpringContextHolder.getBean(PlayService.class);
        //处理校验信息
        ByteBuf in = (ByteBuf) msg;
        NettyDataVO vo = NettyDataHandler.parseResult(in);
        if (vo == null) {
            log.info("消息处理失败");
            return;
        }
        String deviceNumber = NettyDataHandler.byteToString(vo.getDeviceId());
        /*
        业务逻辑：
        0. 连接返回
        1. 心跳返回
        2. 排队扫码
        3. 确认扫码
        4. 结束游戏
         */
        byte[] resBytes = null;
        if (NettyDataHandler.isConnectReport(vo)) {
            log.info("-------------连接返回-------------");
            //判断设备是否加入系统 若否则断开
            Device device = playService.deviceVerify(deviceNumber);
            if (device == null) {
                log.info("设备未登记: " + deviceNumber);
                ctx.close();
                return;
            }
            resBytes = NettyDataHandler.generateSimpleResponseBytes(vo);
        } else if (NettyDataHandler.isHeartbeatReport(vo)) {
            log.info("-------------心跳返回-------------");
            resBytes = NettyDataHandler.generateSimpleResponseBytes(vo);
        } else if (NettyDataHandler.isEndReport(vo)) {
            log.info("-------------结束游戏返回-------------");
            ScanDataVO scanData = NettyDataHandler.parseEndData(vo.getData());
            String uuid = playService.byteArrayToUuid(scanData.getQrData());
            Long userId = playService.uuidToUserId(uuid);
            if (userId == null) {
                log.info("结束上报：二维码信息中用户不存在/已过期");
                return;
            }
            boolean flag = playService.endCurrent(deviceNumber, userId);
            if (!flag) return;
            resBytes = NettyDataHandler.generateSimpleResponseBytes(vo);
        } else if (NettyDataHandler.isScanReport(vo)) { //扫码
            ScanDataVO scanData = NettyDataHandler.parseScanData(vo.getData());
            String uuid = playService.byteArrayToUuid(scanData.getQrData());
            Long userId = playService.uuidToUserId(uuid);
            Device device = playService.deviceVerify(deviceNumber);
            if (device == null) {
                log.info("设备未登记: " + deviceNumber);
                ctx.close();
                return;
            }
            if (userId == null) {
                log.info("扫码上报：二维码信息中用户不存在/已过期");
                if (scanData.getScanType()[0] == (byte) 0x01) {
                    byte[] resData = new byte[2];
                    resData[0] = (byte) 0x01;
                    resData[1] = (byte) 0x01;
                    resBytes = NettyDataHandler.generateResponseBytes(vo, resData);
                } else if (scanData.getScanType()[0] == (byte) 0x02) {
                    byte[] resData = new byte[3];
                    resData[0] = (byte) 0x02;
                    resBytes = NettyDataHandler.generateResponseBytes(vo, resData);
                }
            } else {
                if (scanData.getScanType()[0] == (byte) 0x01) {
                    log.info("-------------扫码排队返回-------------");
                    //Redis队列操作 业务逻辑
                    boolean joinRes = playService.joinQueue(device, userId, uuid);
                    byte[] resData = new byte[2];
                    resData[0] = (byte) 0x01;
                    resData[1] = (byte) 0x01;
                    resBytes = NettyDataHandler.generateResponseBytes(vo, resData);
                } else if (scanData.getScanType()[0] == (byte) 0x02) {
                    log.info("-------------扫码确认返回-------------");
                    //数据库操作 Redis操作 业务逻辑
                    int ballNumber = 0;
                    ballNumber = playService.confirmScan(device, userId, uuid);
                    byte[] resData = new byte[3];
                    resData[0] = (byte) 0x02;
                    if (ballNumber < 256) {
                        resData[2] = (byte) ballNumber;
                    } else {
                        resData[1] = (byte) (ballNumber / 256);
                        resData[2] = (byte) (ballNumber % 256);
                    }
                    resBytes = NettyDataHandler.generateResponseBytes(vo, resData);
                }
            }
        } else {
            log.info("-------------无法处理的消息类型-------------");
            return;
        }
        //返回值
        if (resBytes != null) {
            ByteBuf res = ctx.alloc().buffer(resBytes.length);
            res.writeBytes(resBytes);
            ctx.writeAndFlush(res);
        }
//        log.info("===== Netty End =====");
    }

    /**
     * 发生异常触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}
